import org.junit.Test;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class LambdaTest {

    /**
     * 使用Lambda表达式遍历List集合
     */
    @Test
    public void testDonat() {

        List<String> features = Arrays.asList("Lambdas", "Default Method",
                "Stream API", "Date and Time API");

        System.out.println("常规循环");
        for (String feature : features) {
            System.out.println(feature);
        }

        System.out.println("lambda循环1");
        features.forEach(n -> System.out.println(n));


        System.out.println("lambda循环2");
        features.forEach(System.out::println);


    }


    /**
     * Lambda表达式和函数接口
     */
    @Test
    public void test2() {
        List<String> languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");

      StringBuilder a = new StringBuilder();
      languages.forEach(n -> a.append(n));
      System.out.println(a);

        System.out.println("Languages which starts with J :");
        filter(languages, (str) -> str.startsWith("J"));

        System.out.println("Languages which ends with a ");
        filter(languages, (str) -> str.endsWith("a"));

        System.out.println("Print all languages :");
        filter(languages, (str) -> true);

        System.out.println("Print no language : ");
        filter(languages, (str) -> false);

        System.out.println("Print language whose length greater than 4:");
        filter(languages, (str) -> str.length() > 4);

    }

    public static void filter(List<String> names, Predicate<String> condition) {
        for (String name : names) {
            if (condition.test(name)) {
                System.out.println(name + " ");
            }
        }
    }

    /**
     * Predicate使用
     * java.util.function.Predicate提供and(), or() 和 xor()可以进行逻辑操作，比如为了得到一串字符串中以"J"开头的4个长度：
     */
    @Test
    public void testPredicate() {
        Predicate<String> startsWithJ = (n) -> n.startsWith("J");
        Predicate<String> fourLetterLong = (n) -> n.length() == 4;
        List<String> languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
        languages.stream()
                .filter(startsWithJ.and(fourLetterLong))
                .forEach((n) -> System.out.print("\nName, which starts with 'J' and four letter long is : " + n));

    }


    /**
     * 构造流
     * 构造流的几种常见方法
     */
    @Test
    public void testStream() {
        // 1. Individual values
        Stream stream = Stream.of("a", "b", "c");
        // 2. Arrays
        String[] strArray = new String[]{"a", "b", "c"};
        stream = Stream.of(strArray);
        stream = Arrays.stream(strArray);
        // 3. Collections
        List<String> list = Arrays.asList(strArray);
        stream = list.stream();

        System.out.println("数组构造stram1");
        IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println);
        System.out.println("数组构造stram2");
        IntStream.range(1, 3).forEach(System.out::println);
        System.out.println("数组构造stram3");
        IntStream.rangeClosed(1, 3).forEach(System.out::println);
    }

    /**
     * 流转换为其它数据结构
     */
    @Test
    public void testStream2() {
        Stream<String> stream = Stream.of("a", "b", "c");
        System.out.println("转换为数组");
        // 1. Array
        String[] strArray1 = stream.toArray(String[]::new);
        for (String str : strArray1) {
            System.out.println(str);
        }
        System.out.println("转换为集合");
        // 2. Collection
        stream = Stream.of("a", "b", "c");
        List<String> list1 = stream.collect(Collectors.toList());
        list1.forEach(n-> System.out.println(n));

//        List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
//        Set set1 = stream.collect(Collectors.toSet());
//        Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
//// 3. String
//        String str = stream.collect(Collectors.joining()).toString();
    }

    /**
     * Stream map用法
     */
    @Test
    public void testStreamMap() {
        List<Integer> nums = Arrays.asList(1, 2, 3, 4);
        List<Integer> squareNums = nums.stream().
                map(n -> n * n).
                collect(Collectors.toList());

        squareNums.forEach(n-> System.out.println(n));
    }

    /**
     * filter用法
     */
    @Test
    public void testFilter(){
        Integer[] sixNums = {1, 2, 3, 4, 5, 6};
        Integer[] evens =
                Stream.of(sixNums).filter(n -> n%2 == 0).toArray(Integer[]::new);
    }

    /**
     * reduce用法
     */
    @Test
    public void testStreamReduce(){
        // 字符串连接，concat = "ABCD"
        String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
        System.out.println(concat);

        // 求最小值，minValue = -3.0
        double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
        System.out.println(minValue);
    }
}
